package com.company.Lock;

import java.util.Scanner;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.LockSupport;

// 手写实现 java lock
// CLH MCS锁概念
public class TonyLock implements Lock {
    // 锁的状态 0-未占用 1-占用
    AtomicInteger state = new AtomicInteger();
    // 当前占用锁的线程
    Thread ownerThread = null;
    // 当前在等待抢锁的线程
    LinkedBlockingQueue<Thread> waiters = new LinkedBlockingQueue<>();

    @Override
    public boolean tryLock() {
        if (state.get() == 0) { // 如果没人加锁，从0改为1代表加锁成功
            if (state.compareAndSet(0, 1)) {
                ownerThread = Thread.currentThread();
                return true;
            }
        } else if (ownerThread == Thread.currentThread()) { // 如果占用锁就是当前线程，则代表重入
            state.set(state.get() + 1); // 当前值加一 state.incrementAndGet();
            return true;
        }
        return false;
    }

    @Override
    public void lock() {
        if (!waiters.isEmpty() || !tryLock()) {// 你要公平怎么办？ --- 要判断是否有排队
            waiters.add(Thread.currentThread()); // 加入等待队列
            for (; ; ) { // 被唤醒后，然后抢锁
                // 进入队列之后要做二次抢锁
                if (waiters.peek() == Thread.currentThread() && tryLock()) { // 公平锁你就不能直接trylock 要判断
                    waiters.poll();
                    return; // 代表抢到锁
                } else {
                    LockSupport.park(); // 进入停车场
                }
            }
        }
    }

    @Override
    public void unlock() {
        if (Thread.currentThread() != ownerThread) {
            throw new IllegalMonitorStateException();
        }
        if (state.decrementAndGet() == 0) { // 减1等于0 -- 0代表锁未被占用
            ownerThread = null;
            // 通知其他线程
            Thread waiterThread = waiters.peek();
            if (waiterThread != null) {
                LockSupport.unpark(waiterThread);
            }
        }


    }

    @Override
    public void lockInterruptibly() throws InterruptedException {

    }


    @Override
    public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
        return false;
    }


    @Override
    public Condition newCondition() {
        return null;
    }

}
